using System;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Linq;
class Program
{
    static void Main()
    {
        Application.Run(new DemoForm());
    }
}

class DemoForm : Form
{
    // Pal基础颜色盒
    Color[] nesColors = new Color[64];
    byte[] defaultPAL = new byte[4];
    Bitmap[] chrBitMap = new Bitmap[256];
    bool isChrData = false;
    int[] debugIndex = new int[64];

    public DemoForm()
    {
        Text = " Pixel ";
        Size = new Size(1024, 1024);
        initPAL();

        // 按钮
        Button openBtn = new Button();
        openBtn.Text = "打开chr";
        openBtn.Parent = this;
        openBtn.Location = new Point(20, 20);
        openBtn.Click += new EventHandler(onOpenChr);

    }

    protected override void OnPaint(PaintEventArgs e)
    {
        // draw256Rect(e.Graphics, 20, 20, 32);
        // draw240Rect(e.Graphics, 600, 20, 32);
        // draw4Rect(e.Graphics,20,20,32);

        if (isChrData)
        {
            drawChrData(e.Graphics);
            // drawIndex(e.Graphics);
        }
    }

    protected void onOpenChr(object sender, EventArgs e)
    {
        // 打开文件选择器
        OpenFileDialog opnDlg = new OpenFileDialog();
        opnDlg.InitialDirectory = ".";
        opnDlg.Filter = "All | *.chr;*.bin";
        opnDlg.Title = "打开chr文件";

        opnDlg.ShowHelp = true; //必须设置

        if (opnDlg.ShowDialog() == DialogResult.OK)
        {
            try
            {
                var path = opnDlg.FileName;
                FileStream fileStream = new FileStream(path, FileMode.Open, FileAccess.Read);
                //定义存放文件信息的字节数组
                byte[] bytes = new byte[fileStream.Length];
                fileStream.Read(bytes, 0, bytes.Length);
                if (bytes.Length % 4096 != 0)
                {
                    MessageBox.Show("chr 必须是4k的倍数大小");
                    return;
                }
                else
                {
                    getChrData(bytes);
                }
            }
            catch (Exception exp)
            {
                MessageBox.Show(exp.Message);
            }
        }

        Invalidate();
    }

    void getChrData(byte[] chrData)
    {
        // chr4k
        byte[]  chr4k = chrData.Skip(0).Take(4096).ToArray();

        byte[] sprPal = {
           0x22,0x16,0x27,0x18,0x0F,0x1A,0x30,0x27,0x0F,0x16,0x30,0x27,0x0F,0x0F,0x36,0x17
        };

        byte[] bgPal = {
            0x22,0x29,0x1A,0x0F,0x0F,0x36,0x17,0x0F,0x0F,0x30,0x21,0x0F,0x0F,0x17,0x17,0x0F
        };

        chrBitMap = chr2Pal(chr4k, sprPal);
        if (chrBitMap == null)
        {
            MessageBox.Show("chrData错误");
        }
        else
        {
            isChrData = true;
        }
    }

    void drawChrData(Graphics g)
    {
        var x = 100;
        var y = 100;
        var interval = 20;

        // 绘制矩形
        draw256Rect(g, x, y, interval);

        for (int i = 0; i < chrBitMap.Length; i++)
        {
            var yi = i / 16;
            var xi = i - (yi * 16);
            g.DrawImage(chrBitMap[i], x + xi * interval + 1, y + yi * interval + 1, interval, interval);
        }
        // 调试信息
    }
    void drawIndex(Graphics g)
    {
        // g.DrawString(debugIndex[0].ToString(),Font,new SolidBrush(ForeColor),100,100);
        var xs = 100;
        var ys = 100;

        for (int i = 0; i < 64; i++)
        {
            var y = i / 8;
            var x = i - (y * 8);
            xs = xs + 32;

            g.DrawString(debugIndex[i].ToString(), Font, new SolidBrush(ForeColor), xs, ys);

            if (x == 7)
            {
                xs = 100;
                ys = ys + 32;
            }
        }
    }

    //绘制16x16的网格矩形
    void draw256Rect(Graphics g, int x, int y, int interval)
    {
        var rectWidth = interval * 16;
        var pen = new Pen(ForeColor);
        for (int i = 0; i <= rectWidth; i = i + interval)
        {
            // 垂直 [i,0] [i,height]
            // 水平 [0,i] [widht,i]
            g.DrawLine(pen, x + i, y + 0, x + i, y + rectWidth);
            g.DrawLine(pen, x + 0, y + i, x + rectWidth, y + i);
        }
    }

    void draw240Rect(Graphics g, int x, int y, int interval)
    {
        var rectWidth = interval * 16;
        var rectHeight = interval * 15;
        var pen = new Pen(ForeColor);
        for (int i = 0; i <= rectWidth; i = i + interval)
        {
            // 垂直 [i,0] [i,height]
            g.DrawLine(pen, x + i, y + 0, x + i, y + rectHeight);
        }
        for (int i = 0; i <= rectHeight; i = i + interval)
        {
            // 水平 [0,i] [widht,i]
            g.DrawLine(pen, x + 0, y + i, x + rectWidth, y + i);
        }
    }
    void draw4Rect(Graphics g, int x, int y, int interval)
    {
        var brush = new SolidBrush(ForeColor);
        for (int i = 0; i < defaultPAL.Length; i = i + 1)
        {
            brush.Color = nesColors[defaultPAL[i]];
            g.FillRectangle(brush, x + interval * i, y, interval, interval);

        }
    }
    // 4kb的chr转换为pal索引
    // chrData 4k的chr
    // paleete 16个pal索引
    // palSlot 颜色槽
    Bitmap[] chr2Pal(byte[] chrData, byte[] pallete, int palSlot = 0)
    {
        if (chrData.Length != 4096)
        {
            return null;
        }
        var palColors = new Bitmap[256];
        // 256个chr
        for (int i = 0; i < 256; i++)
        {
            Bitmap res = new Bitmap(8, 8);
            // 对应字节开始
            int beginIndex = 16 * i;
            // 8x8的chr块
            for (int line = 0; line < 8; line++)
            {
                for (int pixel = 0; pixel < 8; pixel++)
                {
                    // 前8位
                    bool bitLo = getBit(chrData[beginIndex + line], 7 - pixel);
                    // 后8位
                    bool bitHi = getBit(chrData[beginIndex + line + 8], 7 - pixel);

                    // 颜色索引
                    int tempIndex = (bitHi ? 1 : 0) << 1 | (bitLo ? 1 : 0);
                    int fullPalIndex = palSlot * 4 + tempIndex;

                    // 调试第一个
                    if (i == 0)
                    {
                        debugIndex[line * 8 + pixel] = tempIndex;
                    }

                    int colorNo = pallete[fullPalIndex];
                    Color c = nesColors[colorNo];
                    res.SetPixel(pixel, line, c);
                }
            }

            palColors[i] = res;
        }

        return palColors;
    }

    // 读取from中的第index位的bit
    bool getBit(byte from, int index)
    {
        return (from & (1 << index)) != 0;
    }

    byte[] palIndex2Chr(int[] palIndex)
    {
        var chrByte = new byte[4096];

        return chrByte;
    }

    void initPAL()
    {
        nesColors[0] = Color.FromArgb(124, 124, 124);
        nesColors[1] = Color.FromArgb(0, 0, 252);
        nesColors[2] = Color.FromArgb(0, 0, 188);
        nesColors[3] = Color.FromArgb(68, 40, 188);
        nesColors[4] = Color.FromArgb(148, 0, 132);
        nesColors[5] = Color.FromArgb(168, 0, 32);
        nesColors[6] = Color.FromArgb(168, 16, 0);
        nesColors[7] = Color.FromArgb(136, 20, 0);
        nesColors[8] = Color.FromArgb(80, 48, 0);
        nesColors[9] = Color.FromArgb(0, 120, 0);
        nesColors[0xA] = Color.FromArgb(0, 104, 0);
        nesColors[0xB] = Color.FromArgb(0, 88, 0);
        nesColors[0xC] = Color.FromArgb(0, 64, 88);
        nesColors[0xD] = Color.FromArgb(0, 0, 0);
        nesColors[0xE] = Color.FromArgb(0, 0, 0);
        nesColors[0xF] = Color.FromArgb(0, 0, 0);

        nesColors[0x10] = Color.FromArgb(188, 188, 188);
        nesColors[0x11] = Color.FromArgb(0, 120, 248);
        nesColors[0x12] = Color.FromArgb(0, 88, 248);
        nesColors[0x13] = Color.FromArgb(104, 68, 252);
        nesColors[0x14] = Color.FromArgb(216, 0, 204);
        nesColors[0x15] = Color.FromArgb(228, 0, 88);
        nesColors[0x16] = Color.FromArgb(248, 56, 0);
        nesColors[0x17] = Color.FromArgb(228, 92, 16);
        nesColors[0x18] = Color.FromArgb(172, 124, 0);
        nesColors[0x19] = Color.FromArgb(0, 184, 0);
        nesColors[0x1A] = Color.FromArgb(0, 168, 0);
        nesColors[0x1B] = Color.FromArgb(0, 168, 68);
        nesColors[0x1C] = Color.FromArgb(0, 136, 136);
        nesColors[0x1D] = Color.FromArgb(0, 0, 0);
        nesColors[0x1E] = Color.FromArgb(0, 0, 0);
        nesColors[0x1F] = Color.FromArgb(0, 0, 0);

        nesColors[0x20] = Color.FromArgb(248, 248, 248);
        nesColors[0x21] = Color.FromArgb(60, 188, 252);
        nesColors[0x22] = Color.FromArgb(104, 136, 252);
        nesColors[0x23] = Color.FromArgb(152, 120, 248);
        nesColors[0x24] = Color.FromArgb(248, 120, 248);
        nesColors[0x25] = Color.FromArgb(248, 88, 152);
        nesColors[0x26] = Color.FromArgb(248, 120, 88);
        nesColors[0x27] = Color.FromArgb(252, 160, 68);
        nesColors[0x28] = Color.FromArgb(248, 184, 0);
        nesColors[0x29] = Color.FromArgb(184, 248, 24);
        nesColors[0x2A] = Color.FromArgb(88, 216, 84);
        nesColors[0x2B] = Color.FromArgb(88, 248, 152);
        nesColors[0x2C] = Color.FromArgb(0, 232, 216);
        nesColors[0x2D] = Color.FromArgb(120, 120, 120);
        nesColors[0x2E] = Color.FromArgb(0, 0, 0);
        nesColors[0x2F] = Color.FromArgb(0, 0, 0);

        nesColors[0x30] = Color.FromArgb(252, 252, 252);
        nesColors[0x31] = Color.FromArgb(164, 228, 252);
        nesColors[0x32] = Color.FromArgb(184, 184, 248);
        nesColors[0x33] = Color.FromArgb(216, 184, 248);
        nesColors[0x34] = Color.FromArgb(248, 184, 248);
        nesColors[0x35] = Color.FromArgb(248, 164, 192);
        nesColors[0x36] = Color.FromArgb(240, 208, 176);
        nesColors[0x37] = Color.FromArgb(252, 224, 168);
        nesColors[0x38] = Color.FromArgb(248, 216, 120);
        nesColors[0x39] = Color.FromArgb(216, 248, 120);
        nesColors[0x3A] = Color.FromArgb(184, 248, 184);
        nesColors[0x3B] = Color.FromArgb(184, 248, 216);
        nesColors[0x3C] = Color.FromArgb(0, 252, 252);
        nesColors[0x3D] = Color.FromArgb(248, 216, 248);
        nesColors[0x3E] = Color.FromArgb(0, 0, 0);
        nesColors[0x3F] = Color.FromArgb(0, 0, 0);

        defaultPAL[0] = 0x0F;
        defaultPAL[1] = 0x00;
        defaultPAL[2] = 0x00;
        defaultPAL[3] = 0x12;
    }

    void d(String s)
    {
        MessageBox.Show(s);
    }
}

// 像素矩形
class PixelRect:UserControl{
    int x = 0;
    int y = 0;

    int width;
    int height;
    int interval;

    public PixelRect(
        int w,
        int h,
        int interval
    ){
        this.width = w;
        this.height = h;
        this.interval = interval;
        this.Click += new EventHandler(on_click);
    }

    public PixelRect(){
        this.width = 16;
        this.height = 16;
        this.interval = 32;
        this.Click += new EventHandler(on_click);
    }

    public void setX(int x){
        this.x = x;
    }
    public void setY(int y){
        this.y = y;
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        
    }

    void on_click(object sender,EventArgs e){
        
    }
}
 